"""Three Blocks — Cinema 4D hub plugin entry point.

Cinema 4D scans plugin folders once, at application startup, and Maxon is
explicit that plugins cannot be registered or unregistered later. So this file
does the one thing it is allowed to do at boot — put its own folder on sys.path
and register a CommandData — and nothing else. The package, the credential
store, and the network all wait for the first time the panel is opened.

Managed tools bypass this entirely (they are plain packages the hub imports at
runtime), which is why installing a TOOL never needs a restart, while updating
the hub itself does. See docs/plans/three-blocks-cinema4d-addon.md §5.
"""

import os
import sys

import c4d

# Dev-range ids (1000001–1000010) until the Plugin Café block is reserved.
# Keep in sync with three_blocks/prefs.py's HUB_ID — the same world data.
PLUGIN_ID_HUB = 1000001
PLUGIN_ID_BRIDGE = 1000009

_HERE = os.path.dirname(os.path.abspath(__file__))
if _HERE not in sys.path:
    sys.path.insert(0, _HERE)


class ThreeBlocksHubCommand(c4d.plugins.CommandData):
    """Opens the dockable hub panel, and restores it inside saved layouts."""

    def __init__(self):
        self._dialog = None

    def _get_dialog(self):
        if self._dialog is None:
            from three_blocks import dialog  # imported on first open, not at boot

            self._dialog = dialog.HubDialog()
        return self._dialog

    def Execute(self, doc):
        return self._get_dialog().Open(
            c4d.DLG_TYPE_ASYNC,
            pluginid=PLUGIN_ID_HUB,
            defaultw=340,
            defaulth=220,
        )

    def RestoreLayout(self, secret):
        return self._get_dialog().Restore(pluginid=PLUGIN_ID_HUB, secret=secret)


class ThreeBlocksBridgeHandler(c4d.plugins.MessageData):
    """Main-thread drain for the live bridge (`three-blocks c4d …`).

    The bridge's socket thread queues scene ops + SpecialEventAdd; this runs
    them where Cinema 4D allows scene access. Always registered — C4D only
    allows registration at startup, so registering it here is what lets the
    panel's Live bridge toggle work without a restart. It does nothing at all
    until the bridge is actually running.
    """

    def CoreMessage(self, cid, bc):
        if cid == PLUGIN_ID_HUB and "three_blocks.bridge" in sys.modules:
            try:
                sys.modules["three_blocks.bridge"].drain_jobs()
            except Exception:
                pass
        return True


def PluginMessage(cid, data):
    # Auto-start only when asked (TB_C4D_BRIDGE=1, or the remembered panel
    # toggle) — importing the package reads prefs, so keep it inside the guard.
    if cid == c4d.C4DPL_PROGRAM_STARTED:
        try:
            from three_blocks import bridge

            if bridge.enabled():
                bridge.start()
        except Exception as error:  # the hub must never break C4D startup
            print(f"three_blocks: bridge failed to start: {error}")
    elif cid == c4d.C4DPL_ENDPROGRAM and "three_blocks.bridge" in sys.modules:
        try:
            sys.modules["three_blocks.bridge"].stop()
        except Exception:
            pass
    return True


if __name__ == "__main__":
    c4d.plugins.RegisterCommandPlugin(
        id=PLUGIN_ID_HUB,
        str="Three Blocks",
        info=0,
        icon=None,
        help="Manage Three Blocks tools — installed tools stay local",
        dat=ThreeBlocksHubCommand(),
    )
    c4d.plugins.RegisterMessagePlugin(
        id=PLUGIN_ID_BRIDGE,
        str="Three Blocks Bridge",
        info=0,
        dat=ThreeBlocksBridgeHandler(),
    )
